package api

import (
	"context"
	"net/http"
	"strconv"
	"time"
	"user_api/global"
	"user_api/middleware"
	"user_api/models/request"
	"user_api/models/response"
	pb "user_api/proto"
	"user_api/util"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// PostCreateUser 新建用户
func PostCreateUser(c *gin.Context) {

	// 表单验证
	var req request.CreateUserReq
	if err := c.ShouldBindJSON(&req); err != nil {
		HandleValidatorError(c, err)
		return
	}

	// TODO: 可能是用户名已经存在之类的错误，错误吗处理
	resp, err := global.UserRpcClient.CreateUser(context.Background(), &pb.CreateUserRequest{
		Username: req.Username,
		Password: req.Password,
		Role:     uint32(req.Role),
	})

	if err != nil {
		zap.L().Error("user rpc 微服务调用失败",
			zap.Error(err),
			zap.String("username",
				req.Username),
		)
		c.JSON(http.StatusOK, response.Response{
			Code:    http.StatusBadRequest,
			Message: "user rpc 微服务调用失败",
		})
		return
	}

	c.JSON(http.StatusOK, response.Response{
		Code:    http.StatusOK,
		Message: "success",
		Data: gin.H{
			"Id": resp.Id,
		},
	})
}

// PostUserLogin 登录用户
func PostUserLogin(c *gin.Context) {
	// 表单验证
	var req request.UserLoginReq
	if err := c.ShouldBindJSON(&req); err != nil {
		HandleValidatorError(c, err)
		return
	}

	isVerified := store.Verify(req.CaptchaId, req.Captcha, true)
	if !isVerified {
		c.JSON(http.StatusBadRequest, response.Response{
			Code:    http.StatusBadRequest,
			Message: "验证码错误",
		})
		return
	}

	// 登录逻辑
	userResp, err := global.UserRpcClient.GetUserByUsername(c, &pb.GetUserByUsernameRequest{
		Username: req.Username,
	})
	if err != nil {
		HandleGRPCError(c, err)
		return
	}
	// 验证密码
	checkResp, err := global.UserRpcClient.CheckPassword(c, &pb.CheckPasswordRequest{
		Password:       req.Password,
		HashedPassword: userResp.HashedPassword,
	})
	if err != nil {
		HandleGRPCError(c, err)
		return
	}
	if !checkResp.Success {
		c.JSON(http.StatusBadRequest, response.Response{
			Code:    http.StatusBadRequest,
			Message: "密码错误",
		})
		return
	}

	// 生成token
	j := middleware.NewJWT()
	claims := request.CustomClaims{
		ID:          uint(userResp.Id),
		NickName:    userResp.Username,
		AuthorityId: uint(userResp.Role),
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(time.Hour * 24 * 30).Unix(),
			IssuedAt:  time.Now().Unix(),
			Issuer:    "user-web",
		},
	}
	token, err := j.CreateToken(claims)
	if err != nil {
		zap.L().Error("生成token失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, response.Response{
			Code:    http.StatusInternalServerError,
			Message: "生成token失败",
		})
		return
	}
	zap.L().Debug("登录成功", zap.Any("username", req.Username), zap.String("token", token))
	c.JSON(http.StatusOK, response.Response{
		Code:    http.StatusOK,
		Message: "success",
		Data: response.UserLoginResponse{
			User: response.User{
				Id:       int(userResp.Id),
				NickName: userResp.Username,
				Role:     int(userResp.Role),
			},
			Token:     token,
			ExpiresAt: int(claims.StandardClaims.ExpiresAt * 1000),
		},
	})
}

// GetUserList 获取用户列表
func GetUserList(c *gin.Context) {

	// 获取参数
	pageNum := c.DefaultQuery("page_num", "0")
	pageSize := c.DefaultQuery("page_size", "10")

	// 验证参数
	page, err := strconv.Atoi(pageNum)
	if err != nil {
		zap.L().Error("参数错误", zap.Error(err))
		c.JSON(http.StatusBadRequest, response.Response{
			Code:    http.StatusBadRequest,
			Message: "参数错误",
		})
		return
	}
	size, err := strconv.Atoi(pageSize)
	if err != nil {
		zap.L().Error("参数错误", zap.Error(err))
		c.JSON(http.StatusBadRequest, response.Response{
			Code:    http.StatusBadRequest,
			Message: "参数错误",
		})
		return
	}

	// 调用方法
	resp, err := global.UserRpcClient.GetUserList(c, &pb.PageInfo{
		PageNum:  uint32(page),
		PageSize: uint32(size),
	})
	if err != nil {
		HandleGRPCError(c, err)
		return
	}

	users := make([]response.User, 0)
	for _, user := range resp.Users {
		userResp := response.User{
			Id:       int(user.Id),
			NickName: user.Username,
			Role:     int(user.Role),
		}
		users = append(users, userResp)
	}
	c.JSON(http.StatusOK, response.Response{
		Code:    http.StatusOK,
		Message: "success",
		Data: response.UserListResponse{
			Total: resp.Total,
			Users: users,
		},
	})
}

// UpdateUserRole 修改用户的角色
func UpdateUserRole(c *gin.Context) {
	// 表单验证
	var req request.UpdateUserRoleReq
	if err := c.ShouldBindJSON(&req); err != nil {
		HandleValidatorError(c, err)
		return
	}

	_, err := global.UserRpcClient.UpdateUserRole(context.Background(), &pb.UpdateUserRoleRequest{
		Username: req.Username,
		Role:     uint32(req.Role),
	})

	if err != nil {
		HandleGRPCError(c, err)
		return
	}
	c.JSON(http.StatusOK, response.Response{
		Code:    http.StatusOK,
		Message: "success",
	})

}

// UpdateUsername 修改用户的名字
func UpdateUsername(c *gin.Context) {

	// get user calims from context
	claims, _ := c.Get("claims")
	userClaims := claims.(*request.CustomClaims)

	// 表单验证
	var req request.UpdateUsernameReq
	if err := c.ShouldBindJSON(&req); err != nil {
		HandleValidatorError(c, err)
		return
	}

	_, err := global.UserRpcClient.UpdateUserName(context.Background(), &pb.UpdateUserNameRequest{
		Id:       uint32(userClaims.ID),
		Username: req.Username,
	})

	if err != nil {
		HandleGRPCError(c, err)
		return
	}

	c.JSON(http.StatusOK, response.Response{
		Code:    http.StatusOK,
		Message: "success",
	})

}

// DeleteUser 删除用户
func DeleteUser(c *gin.Context) {

	// 表单验证
	var req request.DeleteUsernameReq
	if err := c.ShouldBindUri(&req); err != nil {
		HandleValidatorError(c, err)
		return
	}

	_, err := global.UserRpcClient.DeleteUser(context.Background(), &pb.DeleteUserRequest{
		Username: req.Username,
	})
	if err != nil {
		HandleGRPCError(c, err)
		return
	}

	c.JSON(http.StatusOK, response.Response{
		Code:    http.StatusOK,
		Message: "success",
	})
}

// CreateApikey 创建Apikey
func CreateApikey(c *gin.Context) {

	// get user calims from context
	claims, _ := c.Get("claims")
	userClaims := claims.(*request.CustomClaims)

	resp, err := global.UserRpcClient.CreateApikey(context.Background(), &pb.CreateApikeyRequest{
		Id:     uint32(userClaims.ID),
		Apikey: util.GenerateAPIKey(),
	})

	if err != nil {
		HandleGRPCError(c, err)
		return
	}

	c.JSON(http.StatusOK, response.Response{
		Code:    http.StatusOK,
		Message: "success",
		Data: gin.H{
			"apikey": resp.Apikey,
		},
	})
}

// GetApikey 获取apikey
func GetApikey(c *gin.Context) {

	// get user calims from context
	claims, _ := c.Get("claims")
	userClaims := claims.(*request.CustomClaims)

	resp, err := global.UserRpcClient.GetApikey(context.Background(), &pb.GetApikeyRequest{
		Id: uint32(userClaims.ID),
	})

	if err != nil {
		HandleGRPCError(c, err)
		return
	}

	c.JSON(http.StatusOK, response.Response{
		Code:    http.StatusOK,
		Message: "success",
		Data: gin.H{
			"apikey": resp.Apikey,
		},
	})
}
